#include "stdafx.h"
#include "ZAsyncSocket.h"
#include "ZStream.h"
#include "ZMessageReceiver.h"
#include "ZUtility.h"

#pragma	warning(disable:4355)

namespace	Z	{

//------------------------------------------------------------------------------------------------------------------------
AsyncSocket::AsyncSocket(SOCKET so, NetworkId kNetworkId)
:	Socket(so),
	mNetworkId(kNetworkId),
	mReference(0),
	mReceiveOverlapped(new Overlapped),
	mSendOverlapped(new Overlapped)
{
}

AsyncSocket::~AsyncSocket()
{
	deletePtr(mReceiveOverlapped);
	deletePtr(mSendOverlapped);
}

bool AsyncSocket::create()
{
	return Socket::create(AF_INET, SOCK_STREAM, IPPROTO_TCP, WSA_FLAG_OVERLAPPED);
}

bool AsyncSocket::send(Stream* pStream)
{
	mutex_t::scoped_lock		lock(mSendLock);

	if(mSendBuffer.add(pStream))	{
		reference();
		if(!doSend())	{
			unreference();
			return false;
		}
	}
	return true;
}

bool AsyncSocket::doSend()
{
	const size_t kMaxWsaBufCount	= 8;
	const size_t kWsaBufCount	= std::min<size_t>(mSendBuffer.getWsaBufCount(), kMaxWsaBufCount);
	if(kWsaBufCount == 0)	{
		if(unreference())	{
			reference();
			return false;
		}
		return true;
	}

	WSABUF kWsaBufs[kMaxWsaBufCount];
	mSendBuffer.getWsaBufs(kWsaBufs, kWsaBufCount);
	zeroise(*mSendOverlapped);
	const bool result	= Socket::send(kWsaBufs, kWsaBufCount, mSendOverlapped);
	return result;
}

bool AsyncSocket::onSendComplete(size_t bytesTransferred)
{
	mutex_t::scoped_lock		lock(mSendLock);

	mSendBuffer.onComplete(bytesTransferred);
	return doSend();
}

bool AsyncSocket::receive()
{
	mReceiveBuffer.reserve(Stream::autoSize);
	const size_t kMaxWsaBufCount	= 8;
	WSABUF kWsaBufs[kMaxWsaBufCount];
	const size_t kWsaBufCount	= std::min<size_t>(mReceiveBuffer.getWsaBufCount(), kMaxWsaBufCount);
	mReceiveBuffer.getWsaBufs(kWsaBufs, kWsaBufCount);
	zeroise(*mReceiveOverlapped);
	const bool result	= Socket::receive(kWsaBufs, kWsaBufCount, mReceiveOverlapped);
	return result;
}

bool AsyncSocket::onReceiveComplete(size_t bytesTransferred, MessageReceiver& kMessageReceiver)
{
	mReceiveBuffer.onComplete(bytesTransferred);
	kMessageReceiver.onReceive(mReceiveBuffer, *this);
	return receive();
}

}